package com.cjm.concurrenttest;

import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Slf4j
public class TestGuardedObject{
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            new People().start();
        }

        TimeUnit.SECONDS.sleep(1);

        for (Integer id : MailBoxes.getIds()) {
            new Postman(id, id + "送出信").start();
        }
    }
}

@Slf4j
class People extends Thread{
    @Override
    public void run() {
        //收信
        GuardedObjectTest guardedObject = MailBoxes.createGuardedObject();
        log.debug("收信前, id:{}", guardedObject.getId());
        Object res = guardedObject.get(5000);
        log.debug("收信后, id:{}，内容：{}", guardedObject.getId(), res);

    }
}

@Slf4j
class Postman extends Thread{
    //对应邮箱
    private int id;

    private String mail;

    public Postman(int id, String mail) {
        this.id = id;
        this.mail = mail;
    }

    @Override
    public void run() {
        GuardedObjectTest guardedObject = MailBoxes.getGuuardedObject(id);
        log.debug("送信前, id:{}", guardedObject.getId());
        guardedObject.complete(mail);
        log.debug("送信前, id:{}，内容：{}", guardedObject.getId(), mail);
    }
}

class MailBoxes {
    private static Map<Integer, GuardedObjectTest> boxes = new ConcurrentHashMap<>();

    private static int id = 1;

    //可以用乐观锁和atomicInteger代替sync
    private static synchronized int generatedId(){
        return id++;
    }

    public static GuardedObjectTest getGuuardedObject(int id){
        return boxes.remove(id);
    }

    public static GuardedObjectTest createGuardedObject(){
        GuardedObjectTest go =  new GuardedObjectTest(generatedId());
        boxes.put(go.getId(), go);
        return go;
    }

    public static Set<Integer> getIds(){
        return boxes.keySet();
    }
}

class GuardedObjectTest {
    //标识对象
    private int id;
    //产生的结果
    private Object response;
    //用于锁
    private final Object lock = new Object();

    public int getId() {
        return id;
    }

    public GuardedObjectTest(int id) {
        this.id = id;
    }


    public Object get(long timeout){
        synchronized (this) {
            //开始时间
            long begin = System.currentTimeMillis();
            //经历的时间
            long passedTime = 0;

            while (response == null) {
                long waitTime = timeout - passedTime;
                if(waitTime <= 0){
                    break;
                }
                try {
                    this.wait(waitTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //求得所经历的时间
                passedTime = System.currentTimeMillis() - begin;
            }
            return response;
        }
    }

    public void complete(Object response) {
        synchronized (this) {
            this.response = response;
            this.notifyAll();
        }
    }
}
